package servlet;

import mapper.*;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * Minicat的主类
 */
public class Bootstrap {


    /**
     * 用于存储初始化加载到的Servlet信息
     */
    private static Mapper mapper = new Mapper();

    /**
     * 定义当前解析的项目
     */
    private String contextName = null;

    /**
     * Minicat的v4.0版本
     * 主要是实现作业的要求
     */
    private void  start() throws Exception {


        //1. 加载server.xml，顺带解析webapp下的各个项目的web.xml。封装Mapper、Host
        loadServer();

        //2. 通过webappsPath路径，递归文件，封装contex。获取web.xml进行解析，封装Wrapper以及servlet
        locatonServlet(mapper.getWebappsPath());

        //3.初始化线程池
        ThreadPoolExecutor threadPoolExecutor = initExecutor();

        //4.创建socket
        ServerSocket serverSocket = new ServerSocket(mapper.getPort());

        //5.多线程使用（线程池）进行监听请求
        while(true){
            Socket socket = serverSocket.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket, mapper);
            threadPoolExecutor.execute(requestProcessor);
        }
    }

    public void loadServer(){
        try {
            InputStream inputStream = Bootstrap.class.getClassLoader().getResourceAsStream("server.xml");
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(inputStream);
            Element rootElement = document.getRootElement();
            Element serverElement = (Element) rootElement.selectSingleNode("//server");
            Element connector = (Element) serverElement.selectSingleNode("//Connector");
            Element engine = (Element) connector.selectSingleNode("//Engine");
            Element hostElement = (Element) engine.selectSingleNode("//Host");

            //获取配置文件的关键信息
            int port = Integer.valueOf(connector.attributeValue("port")).intValue(); //  8080
            String hostName = hostElement.attributeValue("name");   //  localhost
            String webappsPath = hostElement.attributeValue("appBase"); //   D:/IDEA-detailSourceCode-space/webapps

            //封装mapper
            Host host = new Host(hostName);
            //存储监听端口
            mapper.setPort(port);
            //存储webapps路径
            mapper.setWebappsPath(webappsPath);// D:/IDEA-detailSourceCode-space/webapps
            //封装Host
            mapper.setHost(host);

        } catch (DocumentException e) {
            e.printStackTrace();
        }

    }

    private void locatonServlet(String path) {
        try {
            File file = new File(path);
            if(file.exists()){
                if(file.isDirectory()){
                    File[] files = file.listFiles();
                    for (File file1 : files) {
                        //D:\IDEA-detailSourceCode-space\webapps\demo1或者demo2
                        //默认认为webapps下文件为项目文件，如果当前处理webapps下的demo1、demo2文件，那么将进行context的封装
                        //mapper.getWebappsPath().replaceAll("/","\\\\") D:\IDEA-detailSourceCode-space\webapps
                        if(file.exists() && file.isDirectory() && file1.getParentFile().getPath().equals(mapper.getWebappsPath().replaceAll("/","\\\\"))){
                            //封装context存储到Host
                            Context context = new Context(file1.getName()); //file1.getName()    demo1 、demo2
                            List<Context> contexts = mapper.getHost().getContexts();
                            contexts.add(context);
                            mapper.getHost().setContexts(contexts);
                            contextName = context.getName();
                        }

                        locatonServlet(file1.getPath());
                    }
                }else if(file.isFile() && file.getName().endsWith(".xml")){
                    /**
                     * 加载解析webapp下面的各个项目的web.xml文件，初始化Servlet
                     */
                    loadServlet(file);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 加载解析web.xml文件，初始化Servlet
     */
    private void loadServlet(File file) {

        try {
            InputStream resourceAsStream = new FileInputStream(file); //  D:/IDEA-detailSourceCode-space/webapps/web.xml

            //进行web.xml的解析，用到dom4j进行解析，所以引入pom坐标
            //获取配置文件输入流
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(resourceAsStream);
            //获取根节点
            Element rootElement = document.getRootElement();
            Element servleElement = (Element) rootElement.selectSingleNode("//servlet");

            //<servlet-name>lagou</servlet-name>
            Element servletNameElement = (Element) servleElement.selectSingleNode("servlet-name");
            String servletName = servletNameElement.getStringValue();
            //<servlet-class>servlet.LagouServlet</servlet-class>
            Element servletClassElement = (Element) servleElement.selectSingleNode("servlet-class");
            String servletClass = servletClassElement.getStringValue();

            //根据servlet-name找到servlet-mapping(servlet-name等于lagou的)
            Element servletMappingElement = (Element) rootElement.selectSingleNode("/webapp/servlet-mapping[servlet-name='" + servletName + "']");
            //   /laogu
            String urlPattern = servletMappingElement.selectSingleNode("url-pattern").getStringValue();


            //先进行web.xml的加载，然后通过遍历Contexts，和当前contextName进行匹配，判断当前web.xml属于哪个项目（context）
            for (Context context : mapper.getHost().getContexts()) {
                //判断当前的contextName不一致，则跳过
                if(!contextName.equals(context.getName()))
                    continue;

                //解析web.xml，实例化servlet-class标签的servlet
                MyClassLoader myClassLoader = new MyClassLoader(mapper.getWebappsPath()+"/"+context.getName());
                Class<?> aClass = myClassLoader.findClass(servletClass);

                //创建Wrapper
                Wrapper wrapper = new Wrapper(urlPattern.replaceAll("/",""));
                //将url和servletMapping进行映射，封装到wrapper
                wrapper.setHttpServlet((HttpServlet) aClass.newInstance());
                //封装到context的wrapper集合
                context.getWrappers().add(wrapper);
                //将动态请求链接进行存储
                mapper.getServletUrlList().add("/"+context.getName()+urlPattern);
            }

        } catch (DocumentException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }


    private ThreadPoolExecutor initExecutor(){
        int corePoolSize = 10;
        int maximumPoolSize = 50;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue= new ArrayBlockingQueue<>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);
        return threadPoolExecutor;
    }


    /**
     * Minicat的程序启动入口
     * @param args
     */
    public static void main(String[] args) throws Exception {

        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        }


    }


}
